﻿package com.wky.common.dao.impl;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.persister.entity.SingleTableEntityPersister;
import org.hibernate.util.EmptyIterator;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.wky.common.dao.ICommonDao;
import com.wky.common.page.Page;

public class CommonDaoImpl extends HibernateDaoSupport implements
		ICommonDao {
	/** hibernate 的batchSize值 */
	private Integer hibernateBatchSize = new Integer(30);

	public Session getHibernateSession() {
		return super.getSession();
	}

	public int getHibernateFetchSize() {
		return super.getHibernateTemplate().getFetchSize();
	}

	public int getHibernateBatchSize() {
		return this.hibernateBatchSize.intValue();
	}

	public void flushAndClearCache() {
		super.getSession().flush();
		super.getSession().clear();

	}

	public void insert(Object entity) {
		super.getHibernateTemplate().save(entity);
	}

	public void update(Object entity) {
		super.getHibernateTemplate().update(entity);
	}

	public void save(Object entity) {
		super.getHibernateTemplate().saveOrUpdate(entity);
		super.getHibernateTemplate().flush();
	}

	public void saveAndRefresh(Object entity) {
		super.getHibernateTemplate().saveOrUpdate(entity);
		super.getHibernateTemplate().flush();
		super.getHibernateTemplate().refresh(entity);
	}

	public void saveAll(Collection<Object> entities) {
		super.getHibernateTemplate().saveOrUpdateAll(entities);
	}

	public void delete(Object entity) {
		super.getHibernateTemplate().delete(entity);
	}

	public void deleteAll(Collection<Object> entities) {
		super.getHibernateTemplate().deleteAll(entities);
		super.getHibernateTemplate().flush();
	}

	public void deleteAll(Class<Object> entity) {
		super.getHibernateTemplate().bulkUpdate(
				"delete from " + entity.getName());
	}

	public void deleteByBulk(Class<Object> entity, Object id) {
		AbstractEntityPersister meta = (SingleTableEntityPersister) super
				.getSessionFactory().getClassMetadata(entity);
		StringBuffer sql = new StringBuffer("delete from ").append(
				entity.getName()).append(" where ").append(
				meta.getIdentifierColumnNames()[0]).append("=?");
		try {
			super.getHibernateTemplate().bulkUpdate(sql.toString(),
					new Object[] { id });
		} catch (Exception ex) {
			ex.printStackTrace();
			throw new RuntimeException(ex);
		}
	}

	public void updateByBulk(String updateStirng, Object[] values) {
		try {
			super.getHibernateTemplate().bulkUpdate(updateStirng, values);
		} catch (Exception ex) {
			ex.printStackTrace();
			throw new RuntimeException(ex);
		}
	}

	public Object load(Class<?> entityClass, Serializable id) {
		return super.getHibernateTemplate().get(entityClass, id);
	}

	public List<?> loadAll(Class<?> entityClass) {
		return super.getHibernateTemplate().loadAll(entityClass);
	}

	public void initialize(Object proxy) {
		super.getHibernateTemplate().initialize(proxy);
	}

	public List<?> executeSql(String queryString) {
		return super.getHibernateTemplate().find(queryString);
	}

	public List<?> executeSql(String queryString, Object[] values) {
		return super.getHibernateTemplate().find(queryString, values);
	}

	// ////////分页查询
	/** from 令牌标识 */
	private static String sqlFromToken = " from ";
	/** select 令牌标识 */
	private static String sqlSelectToken = "select ";
	/** distinct 令牌标识 */
	private static String sqlDistinctToken = "distinct";
	/** group by 令牌标识 */
	private static String sqlGroupByToken = "group by ";
	/** order by 令牌标识 */
	private static String sqlOrderByToken = "order by ";


	/** 缺省每页显示行数. */
	private int DEFAUT_PAGESIZE = 20;

	public int getDefaultSize() {
		return this.DEFAUT_PAGESIZE;
	}


	public CommonDaoImpl() {
		// 在Spring上下文初始化对象的时候，数据库实现的SystemData中还没有初始化完“分页”数据，所以修改初始化defaultSize的机制。
	}

	/**
	 * 取得查询计划总记录数的HSQL.
	 *
	 * @param queryString
	 *            查询数据的HSQL
	 * @return 查询总记录数的HSQL
	 */
	private String getCountString(final String queryString) {
		String countTokenString = "*";
		String targetString = queryString.toLowerCase();
		int fromPos = targetString.indexOf(sqlFromToken);
		String fromTokenString = queryString.substring((fromPos < 0) ? 0
				: fromPos);
		int orderPos = fromTokenString.indexOf(sqlOrderByToken);
		if (orderPos > 0) {
			fromTokenString = fromTokenString.substring(0, orderPos);
		}
		if (fromPos > 0) {
			int selectPos = targetString.indexOf(sqlSelectToken);
			int distinctPos = targetString.indexOf(sqlDistinctToken);
			if (selectPos >= 0 && distinctPos >= 0) {
				countTokenString = queryString.substring(selectPos
						+ sqlSelectToken.length(), fromPos);
				String[] tokenArray = countTokenString.split(",");
				if (tokenArray.length > 0) {
					countTokenString = tokenArray[0];
				}
			}

		}
		return new StringBuffer().append("select count(").append(
				countTokenString).append(") ").append(fromTokenString)
				.toString();
	}

	/**
	 * 获取总记录数，在兼容以往处理机制的基础上，增加对分组数据的处理
	 *
	 * @param queryString
	 *            查询语句
	 * @param iterator
	 *            执行getCountString后返回的迭代器
	 * @return 总记录数
	 */
	private int getRecordNumber(final String queryString, Iterator<?> iterator) {
		int recordNumber = 0;
		if (queryString.indexOf(sqlGroupByToken) > 0) {
			while (iterator.hasNext()) {
				recordNumber++;
				iterator.next();
			}
		} else if (iterator.hasNext()) {
			recordNumber = ((Long) iterator.next()).intValue();
		}
		if (!(iterator instanceof EmptyIterator)) {
			super.getHibernateTemplate().closeIterator(iterator);
		}
		return recordNumber;

	}

	public Page<?> find(String queryString, int pageNumber) {
		return this.find(queryString, pageNumber, getDefaultSize());
	}
	
	@SuppressWarnings("unchecked")
	public Page<?> find(final String queryString, final int pageNumber,
			final int pageSize) {
		Iterator<Object> iterator = super.getHibernateTemplate().iterate(
				this.getCountString(queryString));

		int recordNumber = this.getRecordNumber(queryString, iterator);

		if (recordNumber == 0) {
			return new HibernatePage<Object>();
		}

		final HibernatePage<Object> page = new HibernatePage<Object>(pageSize, pageNumber,
				recordNumber);

		List<Object> data = (List<Object>) super.getHibernateTemplate().execute(
				new HibernateCallback<Object>() {
					public Object doInHibernate(Session session)
							throws HibernateException {
						Query queryObject = session.createQuery(queryString);
						queryObject.setFirstResult((page.getPageNumber() - 1)
								* pageSize);
						queryObject.setMaxResults(pageSize);
						return queryObject.list();
					}
				});

		page.setData(data);
		return page;
	}

	public Page<?> find(String queryString, Object value, int pageNumber) {
		return this.find(queryString, value, pageNumber, getDefaultSize());
	}

	@SuppressWarnings("unchecked")
	public Page<?> find(final String queryString, final Object value,
			final int pageNumber, final int pageSize) {

		Iterator<Object> iterator = super.getHibernateTemplate().iterate(
				this.getCountString(queryString), value);
		int recordNumber = this.getRecordNumber(queryString, iterator);

		if (recordNumber == 0) {
			return new HibernatePage<Object>();
		}

		final HibernatePage<Object> page = new HibernatePage<Object>(pageSize, pageNumber,
				recordNumber);

		List<Object> data = (List<Object>) super.getHibernateTemplate().execute(
				new HibernateCallback<Object>() {
					public Object doInHibernate(Session session)
							throws HibernateException {
						Query queryObject = session.createQuery(queryString);
						queryObject.setParameter(0, value);
						queryObject.setFirstResult((page.getPageNumber() - 1)
								* pageSize);
						queryObject.setMaxResults(pageSize);
						return queryObject.list();
					}
				});

		page.setData(data);
		return page;
	}

	public Page<?> find(String queryString, Object[] values, int pageNumber) {
		return this.find(queryString, values, pageNumber, getDefaultSize());
	}

	@SuppressWarnings("unchecked")
	public Page<?> find(final String queryString, final Object[] values,
			final int pageNumber, final int pageSize) {
		Iterator<Object> iterator = super.getHibernateTemplate().iterate(
				this.getCountString(queryString), values);

		int recordNumber = this.getRecordNumber(queryString, iterator);

		if (recordNumber == 0) {
			return new HibernatePage<Object>();
		}

		final HibernatePage<Object> page = new HibernatePage<Object>(pageSize, pageNumber,
				recordNumber);

		List<Object> data = (List<Object>) super.getHibernateTemplate().execute(
				new HibernateCallback<Object>() {
					public Object doInHibernate(Session session)
							throws HibernateException {
						Query queryObject = session.createQuery(queryString);
						for (int i = 0; i < values.length; ++i) {
							queryObject.setParameter(i, values[i]);
						}
						queryObject.setFirstResult((page.getPageNumber() - 1)
								* pageSize);
						queryObject.setMaxResults(pageSize);
						return queryObject.list();
					}
				});

		page.setData(data);
		return page;
	}

	public Page<? extends Object> find(final String queryString, final String fieldString,
			final Object[] values, final int pageNumber) {
		Iterator<?> iterator = super.getHibernateTemplate().iterate(
				this.getCountString(queryString), values);
		int recordNumber = this.getRecordNumber(queryString, (Iterator<?>) iterator);

		if (recordNumber == 0) {
			return new HibernatePage<Object>();
		}
		final HibernatePage<Object> page = new HibernatePage<Object>(getDefaultSize(),
				pageNumber, recordNumber);
		List<?> data = (List<?>) super.getHibernateTemplate().execute(
				new HibernateCallback<Object>() {
					public Object doInHibernate(Session session)
							throws HibernateException {
						Query queryObject = session.createQuery("select "
								+ fieldString + queryString);
						for (int i = 0; i < values.length; ++i) {
							queryObject.setParameter(i, values[i]);
						}
						queryObject.setFirstResult((page.getPageNumber() - 1)
								* getDefaultSize());
						queryObject.setMaxResults(getDefaultSize());

						return queryObject.list();
					}
				});

		page.setData(data);
		return page;
	}

	public Page<? extends Object> putDataToPage(List<?> data) {
		return this.putDataToPage(data, 1);
	}

	public Page<?> putDataToPage(List<?> data, int pageNumber) {
		Page<?> result = new HibernatePage<Object>(100000, pageNumber, data.size());
		result.setData(data);
		return result;
	}

	public void pureCacheObject() {
		super.getHibernateTemplate().flush();
		super.getHibernateTemplate().clear();
	}

	public void setHibernateBatchSize(Integer hibernateBatchSize) {
		this.hibernateBatchSize = hibernateBatchSize;
	}

	class HibernatePage<T> implements Page<T> {
		/** 本页包含的数据. */
		private List<? extends Object> data;
		/**
	     *
	     */
		private int pageSize;
		/** 总页数. */
		private int totalPage;
		/** 当前页码. */
		private int pageNumber;
		/** 总记录数 */
		private int totalSize;

		/**
		 * 构造方法.
		 *
		 * @param pageSize
		 *            每页显示的记录数
		 * @param pageNumber
		 *            当前页码
		 * @param recordNumber
		 *            记录总数
		 */
		HibernatePage(int pageSize, int pageNumber, int recordNumber) {
			this.pageSize = pageSize;
			this.pageNumber = pageNumber;
			this.totalPage = (int) Math.ceil((double) recordNumber
					/ (double) pageSize);
			this.totalSize = recordNumber;
			// 确定当前页
			if (this.pageNumber < 1) {
				this.pageNumber = 1;
			}
			if (this.pageNumber > this.totalPage) {
				this.pageNumber = this.totalPage;
			}
		}

		/**
		 * 构造方法：构造一个空的分页对象.
		 */
		HibernatePage() {
			this.data = Collections.emptyList();
			this.totalPage = 0;
			this.pageNumber = 0;
			// this.pageSize = pageSize;
		}

		public void setData(List<? extends Object> data) {
			this.data = data;
		}

		public List<? extends Object> getData() {
			return this.data;
		}

		public int getTotalPage() {
			return this.totalPage;
		}

		public int getPageNumber() {
			return this.pageNumber;
		}

		public boolean hasPreviousPage() {
			return this.pageNumber > 1;
		}

		public boolean hasNextPage() {
			return this.pageNumber < this.totalPage;
		}

		public int getPageSize() {
			return pageSize;
		}

		public int getTotalSize() {
			return totalSize;
		}

		public Long getRecordNumber() {
			return new Long(totalSize);
		}
	}
}
